-------------------------------------------------------------------------------
--
-- File: ULPI.vhd
-- Author: Gherman Tudor
-- Original Project: USB Device IP on 7-series Xilinx FPGA
-- Date: 2 May 2016
--
-------------------------------------------------------------------------------
-- (c) 2016 Copyright Digilent Incorporated
-- All Rights Reserved
-- 
-- This program is free software; distributed under the terms of BSD 3-clause 
-- license ("Revised BSD License", "New BSD License", or "Modified BSD License")
--
-- Redistribution and use in source and binary forms, with or without modification,
-- are permitted provided that the following conditions are met:
--
-- 1. Redistributions of source code must retain the above copyright notice, this
--    list of conditions and the following disclaimer.
-- 2. Redistributions in binary form must reproduce the above copyright notice,
--    this list of conditions and the following disclaimer in the documentation
--    and/or other materials provided with the distribution.
-- 3. Neither the name(s) of the above-listed copyright holder(s) nor the names
--    of its contributors may be used to endorse or promote products derived
--    from this software without specific prior written permission.
--
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
-- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 
-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
-- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
-- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
-- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--
-------------------------------------------------------------------------------
--
-- Purpose:
-- This module handles ULPI transmissions (NOPID, PID, EXTW, REGW, EXTR, REGR)
-- and reception  
-------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
library UNISIM;
use UNISIM.VComponents.all;

entity ULPI is
    Port (                 
              Ulpi_Clk : in  STD_LOGIC; --ULPI input clock. Generated by the USB PHY
			  reset : in STD_LOGIC; -- Reset siganl from upper layers. Resets all logic in this module
			  
			  --ULPI Bus
			  u_Ulpi_Data : inout  STD_LOGIC_VECTOR(7 downto 0);
              u_Ulpi_Dir : in  STD_LOGIC;
              u_Ulpi_Nxt : in  STD_LOGIC;
              u_Ulpi_Stp : out  STD_LOGIC;
              u_Ulpi_Reset : out  STD_LOGIC;
			  
			  --Command signals for ULPI State machine
			  u_Send_NOOP_CMD : in  STD_LOGIC;
			  u_Send_NOPID_CMD : in  STD_LOGIC;
			  u_Send_PID_CMD : in  STD_LOGIC;
			  u_Send_EXTW_CMD : in  STD_LOGIC;
			  u_Send_REGW_CMD : in  STD_LOGIC;
			  u_Send_EXTR_CMD : in  STD_LOGIC;
			  u_Send_REGR_CMD : in  STD_LOGIC;
			  u_Send_STP_CMD : in  STD_LOGIC; 
			  u_Send_Last : in  STD_LOGIC;
			  u_Send_Err : in  STD_LOGIC;
			  u_USB_Mode : in  STD_LOGIC;
			  
			  --Interface with upper layers
			  u_Tx_Data : in  STD_LOGIC_VECTOR (7 downto 0); -- packet data to be transmitted 
			  u_Tx_Data_En : out  STD_LOGIC;                 -- data strobe; indicates to the upper layers when to place valid data on tx_data
			  u_Tx_Pid : in  STD_LOGIC_VECTOR (3 downto 0);  -- PID field associated with transmit packet (PID) commands
			  u_Tx_Regw_Data : in  STD_LOGIC_VECTOR (7 downto 0);    --Register data associated with the REGW, EXTW commands
			  u_Tx_Reg_Addr : in  STD_LOGIC_VECTOR (7 downto 0);     --Immediate address associated with the REGW, EXTW commands
			  u_Tx_Cmd_Done : out STD_LOGIC;      --NOPID, NOOP, PID, EXTW, REGW, REGR, EXTR command completed, ready for next command
			  u_Tx_Pid_Phase_Done : out STD_LOGIC;			  
			  u_CRC16_En : out STD_LOGIC; --indicates to upper layers to consider the current byte as part of the sequence on which CRC16 is computed
			  u_Ulpi_Dir_Out : out  STD_LOGIC;
			  
			  u_Rx_Data : out  STD_LOGIC_VECTOR (7 downto 0); --data received on the ULPI bus
			  u_Rx_Packet_Received : out  STD_LOGIC; --indicates if u_Rx_Data is packet data
			  u_Rx_Cmd_Received : out  STD_LOGIC; --indicates if u_Rx_Data is packet data
			  u_Rx_Register_Data : out  STD_LOGIC_VECTOR (7 downto 0); --Data received in turn of REGR_CMD or EXTW_CMD
              u_Rx_Register_Data_Received : out STD_LOGIC; -- indicates if u_Rx_Register_Data is valid
              
              --UTMI+ signals
			  u_LineState : out  STD_LOGIC_VECTOR (1 downto 0);
			  u_Vbus : out  STD_LOGIC_VECTOR (1 downto 0);
			  u_RxEvent : out  STD_LOGIC_VECTOR (1 downto 0);
			  u_RxActive  : out  STD_LOGIC;
			  u_ID : out  STD_LOGIC;
			  u_Alt_Int : out  STD_LOGIC;
			  
			  state_ind : out STD_LOGIC_VECTOR(5 downto 0) --for debug purposes
			  );
end ULPI;

architecture Behavioral of ULPI is

constant TXCMD_NOOP	:	STD_LOGIC_VECTOR (7 downto 0) := "00000000";
constant TXCMD_NOPID :	STD_LOGIC_VECTOR (7 downto 0) := "01000000";
constant TXCMD_PID	:	STD_LOGIC_VECTOR (3 downto 0) := "0100";
constant TXCMD_REGR	:	STD_LOGIC_VECTOR (7 downto 0) := "11101110";
constant TXCMD_REGW	:	STD_LOGIC_VECTOR (7 downto 0) := "10101110";
constant TXCMD_EXTR	:	STD_LOGIC_VECTOR (7 downto 0) := "11101111";
constant TXCMD_EXTW	:	STD_LOGIC_VECTOR (7 downto 0) := "10101111";

type state_type is (IDLE, SEND_STP, REGR_END, FSM_ERROR, ABORT, RECEIVE, PID_CMD, PID_DATA, PID_DATA_LAST, PID_STP, PID_DATA_ERR, PID_WAIT_J1, PID_WAIT_J2, PID_WAIT_FSEOP1, PID_WAIT_FSEOP2, PID_WAIT_HSEOP1, PID_WAIT_HSEOP2, PID_WAIT_EOP, NOPID_CMD, NOPID_DATA, NOPID_DATA_LAST, NOPID_STP, REGR_CMD1, REGR_CMD2, REGR_TURN, REGR_DATA, REGW_CMD, REGW_DATA, REGW_STP, EXTW_CMD, EXTW_ADDR, EXTW_DATA, EXTW_STP, EXTR_CMD1, EXTR_CMD2, EXTR_ADDR, EXTR_TURN, EXTR_DATA, EXTR_STP); 
signal u_Ulpi_State, u_Ulpi_Next_State : state_type; 
	
signal u_Ulpi_Dir_q : STD_LOGIC;
signal u_Ulpi_Dir_qq : STD_LOGIC;
signal u_Ulpi_Stp_Fsm : STD_LOGIC;
signal u_Txmux_Out_Data : STD_LOGIC_VECTOR (7 downto 0);
signal u_Txmux_Out_Data_q : STD_LOGIC_VECTOR (7 downto 0);
signal t_data_debug : STD_LOGIC_VECTOR (7 downto 0);
signal u_Txcmd_Code : STD_LOGIC_VECTOR (7 downto 0);
signal u_Txmux_Ctrl_8b_Commands : STD_LOGIC;               --used to select TX_CMDs made up of 8 constant bits : NOPID, EXTW, EXTR  on ULPI bus
signal u_Txmux_Ctrl_Extreg_Addr : STD_LOGIC;              --used to select the extended register address on the ULPI bus
signal u_Txmux_Ctrl_Register_Commands : STD_LOGIC;        --used to select REGW and REGR commands on the ULPI bus
signal u_Txmux_Ctrl_Data : STD_LOGIC;                     --used to select data bytes on ULPI bus
signal u_Txmux_Ctrl_Reg_Data : STD_LOGIC;        --used to select the register data to be written on the ULPI bus
signal u_Txmux_Ctrl_PID_Command : STD_LOGIC;              --used to select PID commands : 4 constant bits (0100) + 4PID bits  on ULPI bus
--signal idle_state : STD_LOGIC;
signal u_Receive_Data : STD_LOGIC_VECTOR (7 downto 0);
signal u_Rx_CMD : STD_LOGIC;
signal u_Rx_CMD_Fsm : STD_LOGIC;
signal u_Reg_Data_Latch: STD_LOGIC;
signal u_Packet_Received: STD_LOGIC;
signal u_Rxdemux_Register_Data : STD_LOGIC_VECTOR (7 downto 0);

signal u_Receive_Data_q : STD_LOGIC_VECTOR (7 downto 0);
signal u_Rxdemux_LineState : STD_LOGIC_VECTOR (1 downto 0);
signal u_Rxdemux_Vbus : STD_LOGIC_VECTOR (1 downto 0);
signal u_Rxdemux_RxEvent : STD_LOGIC_VECTOR (1 downto 0);
signal u_Rxdemux_RxEvent_q : STD_LOGIC_VECTOR (1 downto 0);
signal u_Rxdemux_ID : STD_LOGIC;
signal u_Rxdemux_Alt_Int : STD_LOGIC;

signal state_ind_fsm : STD_LOGIC_VECTOR(5 downto 0);
signal debug_clk : STD_LOGIC := '0';

--attribute mark_debug : string;
--attribute keep : string;

--attribute mark_debug of state_ind : signal is "true";
--attribute keep of state_ind : signal is "true";

--attribute mark_debug of u_Ulpi_Dir : signal is "true";
--attribute keep of u_Ulpi_Dir : signal is "true";
--attribute mark_debug of u_Ulpi_Nxt : signal is "true";
--attribute keep of u_Ulpi_Nxt : signal is "true";
--attribute mark_debug of u_Ulpi_Stp : signal is "true";
--attribute keep of u_Ulpi_Stp : signal is "true";
--attribute mark_debug of u_Receive_Data_q : signal is "true";
--attribute keep of u_Receive_Data_q : signal is "true";
--attribute mark_debug of u_Txmux_Out_Data_q : signal is "true";
--attribute keep of u_Txmux_Out_Data_q : signal is "true";
--attribute mark_debug of u_Ulpi_Stp_Fsm : signal is "true";
--attribute keep of u_Ulpi_Stp_Fsm : signal is "true";
--attribute mark_debug of debug_clk : signal is "true";
--attribute keep of debug_clk : signal is "true";


begin

u_Ulpi_Reset <= reset;
u_Ulpi_Dir_Out <= u_Ulpi_Dir_q;

u_Rx_Register_Data_Received <= u_Reg_Data_Latch;
u_Rx_Data <= u_Receive_Data_q;
u_Rx_Register_Data <= u_Rxdemux_Register_Data;
--rx_en <= rx_data_en;

u_Rxdemux_LineState <= u_Receive_Data(1 downto 0);
u_Rxdemux_Vbus <= u_Receive_Data(3 downto 2);
u_Rxdemux_RxEvent <= u_Receive_Data(5 downto 4);
u_RxEvent <= u_Rxdemux_RxEvent_q;
u_Rxdemux_ID <= u_Receive_Data(6);
u_Rxdemux_Alt_Int <= u_Receive_Data(7);

bidirbuf: for i in 0 to 7 generate
 IOBUF_inst : IOBUF
   generic map (
      DRIVE => 12,
      IOSTANDARD => "DEFAULT",
      SLEW => "SLOW")
   port map (
      O => u_Receive_Data(i),     -- Buffer output
      IO => u_Ulpi_Data(i),   -- Buffer inout port (connect directly to top-level port)
      I => u_Txmux_Out_Data_q(i),     -- Buffer input
      T => u_Ulpi_Dir_q      -- 3-state enable input, high=input, low=output 
   );
end generate;
--decide if rx_data carries data/RXCMD
u_Packet_Received <= u_Ulpi_Dir and u_Ulpi_Nxt;
u_Rx_CMD <= (u_Ulpi_Dir_q and u_Ulpi_Dir) and (not u_Ulpi_Nxt);

RXACTIVE_PROC: process (Ulpi_Clk, u_Packet_Received, u_Rxdemux_RxEvent_q, u_Ulpi_Dir_q)
begin
    if (Ulpi_Clk' event and Ulpi_Clk = '1') then
	    if (reset = '0' or u_Ulpi_Dir = '0') then
            u_RxActive <= '0';
        elsif (u_Ulpi_Dir_q = '1' and u_Packet_Received = '1') then
            u_RxActive <= '1';
	   end if;
	end if;
end process;

STATE_CHANGE: process (Ulpi_Clk) --For debug purposes
begin
	if (Ulpi_Clk' event and Ulpi_Clk = '1') then
        debug_clk <= not debug_clk;
	end if;
end process;

--ULPI output signals are registered
DATA_STP_Q_PROC: process (Ulpi_Clk)
begin
	if (Ulpi_Clk' event and Ulpi_Clk = '1') then
	   if (reset = '0') then
	       u_Txmux_Out_Data_q <= (others => '0');
	       u_Ulpi_Stp <= '0';
	   else
            u_Ulpi_Stp <= u_Ulpi_Stp_Fsm;
            u_Txmux_Out_Data_q <= u_Txmux_Out_Data;
        end if;        
	end if;
end process;

--register receive data/control signals (outputs to upper layers)	
RX_Q_PROC: process(Ulpi_Clk)
	begin
		if(Ulpi_Clk' event and Ulpi_Clk = '1') then
		  if (reset = '0') then
		    u_Rx_Cmd_Received <= '0';
		    u_Ulpi_Dir_q <= '0';
		    u_Ulpi_Dir_qq <= '0';
		    u_Rx_Packet_Received <= '0';
		    u_Receive_Data_q <= (others => '0');
		    u_LineState <= (others => '0');
		    u_Vbus <= (others => '0');
		    u_Rxdemux_RxEvent_q <= (others => '0');
		    u_ID <= '0';
		    u_Alt_Int <= '0';
		    u_Rxdemux_Register_Data <= (others => '0');
		    t_data_debug <= (others => '0');
		    
		  else  
		    t_data_debug <= u_Txmux_Out_Data;
		    u_Rx_Cmd_Received <= u_Rx_CMD;
			u_Ulpi_Dir_q  <= u_Ulpi_Dir;
			u_Ulpi_Dir_qq <= u_Ulpi_Dir_q;
			u_Rx_Packet_Received <= u_Packet_Received;
			u_Receive_Data_q <= u_Receive_Data;
			if((u_Rx_CMD = '1') and (u_Rx_CMD_Fsm = '1')) then
				u_LineState <= u_Rxdemux_LineState;
				u_Vbus <= u_Rxdemux_Vbus;
				u_Rxdemux_RxEvent_q <= u_Rxdemux_RxEvent;
				u_ID <= u_Rxdemux_ID;
				u_Alt_Int <= u_Rxdemux_Alt_Int;			
			elsif ( u_Reg_Data_Latch = '1') then 
			    u_Rxdemux_Register_Data <= u_Receive_Data;
			end if;
		end if;
	   end if;
end process;

--Combinational process that selects the byte to be placed on the ULPI data bus
--It can be a TX Command, Packet Data, PID, Register Address, Register Data
TXMUX_PROC: process(Ulpi_Clk, u_Txmux_Ctrl_Data, u_Txmux_Ctrl_Extreg_Addr, u_Txmux_Ctrl_PID_Command, u_Txmux_Ctrl_8b_Commands, u_Txmux_Ctrl_Register_Commands, u_Tx_Data, u_Tx_Pid, u_Txcmd_Code, u_Tx_Reg_Addr, u_Txmux_Ctrl_Reg_Data, u_Tx_Regw_Data)
	begin
			if(u_Txmux_Ctrl_Data = '1') then
				u_Txmux_Out_Data <= u_Tx_Data;
			elsif (u_Txmux_Ctrl_PID_Command = '1') then
				u_Txmux_Out_Data(3 downto 0) <= u_Tx_Pid;
				u_Txmux_Out_Data(7 downto 4) <= TXCMD_PID;
			elsif (u_Txmux_Ctrl_8b_Commands = '1') then
				u_Txmux_Out_Data <= u_Txcmd_Code;
			elsif (u_Txmux_Ctrl_Register_Commands = '1') then
				u_Txmux_Out_Data(7 downto 6) <= u_Txcmd_Code(7 downto 6);
				u_Txmux_Out_Data(5 downto 0) <= u_Tx_Reg_Addr(5 downto 0);
		    elsif (u_Txmux_Ctrl_Extreg_Addr = '1') then
		        u_Txmux_Out_Data <= u_Tx_Reg_Addr; 
			elsif (u_Txmux_Ctrl_Reg_Data = '1') then
				u_Txmux_Out_Data <= u_Tx_Regw_Data;
			else
				u_Txmux_Out_Data <= (others => '0');
			end if;
end process;

-- ULPI State Machine. Implements the framework required for transmit commands( NOPID,
-- PID, EXTW, REGW, EXTR, REGR) and decodes received data

SYNC_PROC: process (Ulpi_Clk)
   begin
      if (Ulpi_Clk' event and Ulpi_Clk = '1') then
         if (reset = '0') then
            u_Ulpi_State <= IDLE;
            state_ind <= (others => '0');
         else
            u_Ulpi_State <= u_Ulpi_Next_State;
            state_ind <= state_ind_fsm;
         end if;        
      end if;
end process;
 
 
NEXT_STATE_DECODE: process (u_Ulpi_State, u_Ulpi_Dir_q, u_Receive_Data_q ,u_Rx_CMD, u_Send_Last, u_Send_Err, u_Ulpi_Dir, u_Ulpi_Dir_qq, u_USB_Mode, u_Receive_Data, u_Ulpi_Nxt, u_Send_NOPID_CMD, u_Send_PID_CMD,u_Send_REGW_CMD,u_Send_EXTW_CMD,u_Send_REGR_CMD,u_Send_EXTR_CMD,u_Send_NOOP_CMD, u_Send_STP_CMD)
   begin
      --declare default state for next_state to avoid latches
        u_Ulpi_Next_State <= u_Ulpi_State; 
        state_ind_fsm <= "000000"; 
		u_Ulpi_Stp_Fsm <= '0';
		u_Txmux_Ctrl_Data <= '0';
		u_Txmux_Ctrl_Reg_Data <= '0';
		u_Txmux_Ctrl_8b_Commands <= '0';
		u_Txmux_Ctrl_Register_Commands <= '0';
		u_Tx_Data_En <= '0';
		u_Txmux_Ctrl_PID_Command <= '0';
		u_Txcmd_Code <= (others => '0');
		u_Rx_CMD_Fsm <= '0';
		u_Tx_Cmd_Done <= '0';
		u_CRC16_En <= '0';
		u_Txmux_Ctrl_Extreg_Addr <= '0';
		u_Reg_Data_Latch <= '0';
		u_Tx_Pid_Phase_Done <= '0';

      case (u_Ulpi_State) is
         when IDLE =>
            state_ind_fsm <= "000000";
			u_Txmux_Ctrl_8b_Commands <= '1';
			u_Txcmd_Code <= (others => '0');
            if ( u_Ulpi_Dir = '0') then
				if(u_Send_NOPID_CMD = '1') then
					u_Ulpi_Next_State <= NOPID_CMD;
				elsif (u_Send_PID_CMD = '1') then
					u_Ulpi_Next_State <= PID_CMD;
				elsif (u_Send_REGW_CMD = '1') then
					u_Ulpi_Next_State <= REGW_CMD;
				elsif (u_Send_EXTW_CMD = '1') then
					u_Ulpi_Next_State <= EXTW_CMD;
				elsif (u_Send_REGR_CMD = '1') then
					u_Ulpi_Next_State <= REGR_CMD1;
				elsif (u_Send_EXTR_CMD = '1') then
					u_Ulpi_Next_State <= EXTR_CMD1;
				elsif (u_Send_NOOP_CMD = '1') then
					u_Ulpi_Next_State <= IDLE;
			    else
						u_Ulpi_Next_State <= IDLE;
			    end if;
			else
					u_Ulpi_Next_State <= RECEIVE;		
            end if;
--SEND PID_CMD	-- No support for packet abort		
         when PID_CMD =>
            state_ind_fsm <= "000001";
			u_Txmux_Ctrl_PID_Command <= '1';
            if (u_Ulpi_Nxt = '1') then
                u_Txmux_Ctrl_PID_Command <= '0'; 
                u_Txmux_Ctrl_Data <= '1'; 
                u_Tx_Data_En <= '1';
                u_CRC16_En <= '1'; 
		        if (u_Send_Last = '1') then
		            u_Ulpi_Stp_Fsm <= '1'; 
		            u_Ulpi_Next_State <= PID_STP;
		        else 
                    u_Tx_Pid_Phase_Done <= '1';
				    u_Ulpi_Next_State <= PID_DATA;
				end if;
            end if;
				
         when PID_DATA =>
                state_ind_fsm <= "000010";
				u_Txmux_Ctrl_Data <= '1';
				if(u_Ulpi_Nxt = '1') then
				    u_CRC16_En <= '1';
					u_Tx_Data_En <= '1';
					if (u_Send_Last = '1') then
						if (u_Send_Err = '0') then
							u_Ulpi_Next_State <= PID_DATA_LAST;
						else
							u_Ulpi_Next_State <= PID_DATA_ERR;
						end if;
					end if;
				else
				    u_Tx_Data_En <= '0';
				end if;
				
			when PID_DATA_LAST =>	
                state_ind_fsm <= "000011";
                u_Txmux_Ctrl_Data <= '1';
                if(u_Ulpi_Nxt = '1') then	
                    u_Txmux_Ctrl_Data <= '0';
                    u_Ulpi_Stp_Fsm <= '1'; 		
                    u_Ulpi_Next_State <= PID_STP;
                end if;    
				
			when PID_STP =>
			    state_ind_fsm <= "000100";
				u_Ulpi_Next_State <= PID_WAIT_EOP;
				
			when PID_WAIT_EOP =>	
			    state_ind_fsm <= "000101";		
				--if(ulpi_dir = '1') then
					if(u_USB_Mode = '1') then
						u_Ulpi_Next_State <= PID_WAIT_HSEOP1;
					else
						u_Ulpi_Next_State <= PID_WAIT_FSEOP1;
					end if;
				--end if;
				
			when PID_WAIT_HSEOP1 =>
			    if (u_Ulpi_Dir = '1') then
			        u_Ulpi_Next_State <= PID_WAIT_HSEOP2;
			    end if;	
			    
			when PID_WAIT_HSEOP2 =>	
			    state_ind_fsm <= "000110";
				if(u_Ulpi_Dir = '1') then
				    u_Rx_CMD_Fsm <= '1';
					if(u_Receive_Data(1 downto 0) = "00") then
					    u_Tx_Cmd_Done <= '1';
						u_Ulpi_Next_State <= IDLE;
					else
					   u_Ulpi_Next_State <= PID_WAIT_HSEOP1;
					end if;
				end if;
				
			when PID_WAIT_FSEOP1 =>
			    state_ind_fsm <= "000111";
				if(u_Ulpi_Dir = '1') then
				    u_Rx_CMD_Fsm <= '1';
					u_Ulpi_Next_State <= PID_WAIT_FSEOP2;
				end if;			
			
			when PID_WAIT_FSEOP2 =>
			    state_ind_fsm <= "001000";
				if(u_Ulpi_Dir_qq = '1') then 
				    u_Rx_CMD_Fsm <= '1';
					if(u_Receive_Data_q(1 downto 0) = "00") then
						u_Ulpi_Next_State <= PID_WAIT_J1;
					else
						u_Ulpi_Next_State <= FSM_ERROR;
					end if;
				end if;
				
			when PID_WAIT_J1 =>	
				state_ind_fsm <= "001001";	
				if (u_Ulpi_Dir = '1') then
				    u_Rx_CMD_Fsm <= '1';
					u_Ulpi_Next_State <= PID_WAIT_J2;
				end if;

			when PID_WAIT_J2 =>	
			    state_ind_fsm <= "001010";		
				if(u_Receive_Data_q(1 downto 0) = "01") then
				    u_Tx_Cmd_Done <= '1';
					u_Ulpi_Next_State <= IDLE;
				else
					u_Ulpi_Next_State <= FSM_ERROR;
				end if;		
				
			when PID_DATA_ERR =>
			    state_ind_fsm <= "001011";
			    u_Tx_Cmd_Done <= '1';
			    u_Ulpi_Stp_Fsm <= '1';
				u_Txcmd_Code <= (others => '1');
				u_Txmux_Ctrl_8b_Commands <= '1';
				u_Ulpi_Next_State <= IDLE; --The link must wait for an RX_CMD indicating a SE0 to J transition before transmitting another packet : Not implemented
--SEND NOPID
			when NOPID_CMD =>
			    if (u_Ulpi_Dir = '0') then
			        state_ind_fsm <= "001100";
				    u_Txcmd_Code <= TXCMD_NOPID;
				    u_Txmux_Ctrl_8b_Commands <= '1';
                    if (u_Ulpi_Nxt = '1') then
					   u_Txmux_Ctrl_8b_Commands <= '0'; 
					   u_Txmux_Ctrl_Data <= '1'; 
                       u_Ulpi_Next_State <= NOPID_DATA;
                    end if;
                else
                    u_Ulpi_Next_State <= IDLE;
                end if;
				
			when NOPID_DATA =>
			    if (u_Ulpi_Dir = '0') then
			        state_ind_fsm <= "001101";
				    u_Txmux_Ctrl_Data <= '1';
				    if (u_Ulpi_Nxt = '1') then
					   if (u_Send_Last = '1') then
						  u_Ulpi_Next_State <= NOPID_DATA_LAST;
					   end if;
				    end if;
				 else
				    u_Ulpi_Next_State <= ABORT;
				 end if;
				
			when NOPID_DATA_LAST =>
			  if (u_Ulpi_Dir = '0') then
			     state_ind_fsm <= "001110";
			     u_Txmux_Ctrl_Data <= '1';
			     u_Ulpi_Stp_Fsm <= '1'; 
                 u_Ulpi_Next_State <= NOPID_STP;
              else
                 u_Ulpi_Next_State <= ABORT;
              end if;
					
			when NOPID_STP =>
			  if (u_Ulpi_Dir = '0') then
                    state_ind_fsm <= "001111";
                    u_Tx_Cmd_Done <= '1';
                    u_Ulpi_Next_State <= IDLE;
              else
                    u_Ulpi_Next_State <= ABORT;      
              end if;      
--SEND REGW
			when REGW_CMD =>
			    state_ind_fsm <= "010000";
				u_Txcmd_Code <= TXCMD_REGW;
				u_Txmux_Ctrl_Register_Commands <= '1';
                if (u_Ulpi_Dir = '0') then
                    if (u_Ulpi_Nxt = '1') then
                        u_Txmux_Ctrl_Register_Commands <= '0'; 
                        u_Txmux_Ctrl_Reg_Data <= '1'; 
						u_Ulpi_Next_State <= REGW_DATA; 
					end if;
				else
					u_Ulpi_Next_State <= RECEIVE;
            end if;
				
			when REGW_DATA =>
			    state_ind_fsm <= "010001";
                if (u_Ulpi_Dir = '0') then
                    if (u_Ulpi_Nxt = '1') then    
                       u_Ulpi_Stp_Fsm <= '1'; 
                       u_Ulpi_Next_State <= REGW_STP;
                    end if;   
				else
					u_Ulpi_Next_State <= RECEIVE;
            end if;
				
			when REGW_STP => 
			    state_ind_fsm <= "010010";
			    u_Tx_Cmd_Done <= '1';
                u_Ulpi_Next_State <= IDLE;

--SEND EXTW  Not Working!
			when EXTW_CMD =>
			    state_ind_fsm <= "010011";
				u_Txcmd_Code <= TXCMD_EXTW;
				u_Txmux_Ctrl_8b_Commands <= '1';
                if (u_Ulpi_Dir = '0') then
					if(u_Ulpi_Nxt = '1') then
						u_Ulpi_Next_State <= EXTW_ADDR;
					end if;
				else
					u_Ulpi_Next_State <= ABORT;
                end if;
				
			when EXTW_ADDR =>
			   state_ind_fsm <= "010100";
			   u_Txmux_Ctrl_Extreg_Addr <= '1';
               if (u_Ulpi_Dir = '0') then
                    u_Ulpi_Next_State <= EXTW_DATA;
			   else
					u_Ulpi_Next_State <= ABORT;
               end if;

			when EXTW_DATA =>
			    state_ind_fsm <= "010101";
                if (u_Ulpi_Dir = '0') then
                    u_Txmux_Ctrl_Reg_Data <= '1';
                    u_Ulpi_Next_State <= EXTW_STP;
				else
					u_Ulpi_Next_State <= ABORT;
                end if;				

			when EXTW_STP =>
			    state_ind_fsm <= "010110";
                if (u_Ulpi_Dir = '0') then
                    u_Tx_Cmd_Done <= '1';
                    u_Ulpi_Next_State <= IDLE;
					u_Ulpi_Stp_Fsm <= '1';
				else
					u_Ulpi_Next_State <= ABORT;
                end if;
--SEND REGR
			when REGR_CMD1 =>
			    state_ind_fsm <= "010111";
				u_Txcmd_Code <= TXCMD_REGR;
				u_Txmux_Ctrl_Register_Commands <= '1';
                if (u_Ulpi_Dir = '0') then
					if(u_Ulpi_Nxt = '1') then
					    u_Txmux_Ctrl_Register_Commands <= '0'; 
						u_Ulpi_Next_State <= REGR_TURN;
					end if;
				else
					u_Ulpi_Next_State <= RECEIVE;
                end if;

			when REGR_TURN =>
			    state_ind_fsm <= "011000";
				if(u_Ulpi_Dir = '1') then
				    if(u_Ulpi_Nxt = '0') then
				        u_Reg_Data_Latch <= '1'; 
					    u_Ulpi_Next_State <= REGR_DATA;
					else
					    u_Ulpi_Next_State <= RECEIVE;
					end if;   
                end if;
				
			when REGR_DATA =>
			    state_ind_fsm <= "011010";
                if(u_Ulpi_Dir = '0') then
                    u_Ulpi_Next_State <= REGR_END;
                else
                    u_Ulpi_Next_State <= RECEIVE;
                end if;
				
			when REGR_END =>
			    u_Tx_Cmd_Done <= '1';
	            if (u_Ulpi_Dir = '1') then
                    u_Ulpi_Next_State <= RECEIVE;
                else
                    u_Ulpi_Next_State <= IDLE;
                end if;
			    
--SEND EXTR Not Working!

			when EXTR_CMD1 =>
			    state_ind_fsm <= "011011";
				u_Txmux_Ctrl_8b_Commands <= '1';
				u_Txcmd_Code <= TXCMD_EXTR;
                if (u_Ulpi_Dir = '0') then
					if(u_Ulpi_Nxt = '1') then
						u_Ulpi_Next_State <= EXTR_ADDR;
					end if;
				else
					u_Ulpi_Next_State <= RECEIVE;
            end if;
				
			when EXTR_ADDR =>
			    state_ind_fsm <= "011101";
			    u_Txmux_Ctrl_Extreg_Addr <= '1';
                if (u_Ulpi_Dir = '0') then
                    u_Ulpi_Next_State <= EXTR_TURN;
				else
					u_Ulpi_Next_State <= RECEIVE;
                end if;
				
			when EXTR_TURN =>
			    state_ind_fsm <= "011110";
                if (u_Ulpi_Dir = '1') then
                    u_Ulpi_Next_State <= EXTR_DATA;
                end if;	
				
			when EXTR_DATA =>
			    state_ind_fsm <= "011111";
				u_Tx_Cmd_Done <= '1';
				u_Reg_Data_Latch <= '1';
				if (u_Ulpi_Nxt = '0') then
					if (u_Ulpi_Dir = '1') then
						u_Ulpi_Next_State <= RECEIVE;
					else
						u_Ulpi_Next_State <= IDLE;
					end if;				
				end if;
--ABORT
			when ABORT =>
			  state_ind_fsm <= "100000";
              u_Ulpi_Next_State <= IDLE;	
              
            when SEND_STP =>
              state_ind_fsm <= "100010";
              u_Ulpi_Stp_Fsm <= '1';
              if (u_Ulpi_Dir_q = '0') then
                u_Ulpi_Next_State <= IDLE;
              end if;	

                			
--RECEIVE					
			when RECEIVE =>
			    state_ind_fsm <= "100001";
				if(u_Ulpi_Dir = '1') then  
				    if (u_Send_STP_CMD = '1') then
				         u_Ulpi_Stp_Fsm <= '1';   
				         u_Ulpi_Next_State <= SEND_STP;
					elsif(u_Rx_CMD = '1') then
					     u_Rx_CMD_Fsm <= '1';					
					end if;
				else
					u_Ulpi_Next_State <= IDLE;
				end if;

         when others =>
            u_Ulpi_Next_State <= IDLE;
      end case;      
end process;

end Behavioral;
